package cn.charlotte.pit.events.impl;

import cn.charlotte.pit.ThePit;
import cn.charlotte.pit.config.NewConfiguration;
import cn.charlotte.pit.config.PitConfig;
import cn.charlotte.pit.data.PlayerProfile;
import cn.charlotte.pit.events.IEvent;
import cn.charlotte.pit.events.INormalEvent;
import cn.charlotte.pit.medal.impl.challenge.CakeEventMedal;
import cn.charlotte.pit.util.FaweUtils;
import cn.charlotte.pit.util.LocationUtil;
import cn.charlotte.pit.util.aabb.AxisAlignedBB;
import cn.charlotte.pit.util.chat.CC;
import cn.charlotte.pit.util.chat.MessageType;
import cn.charlotte.pit.util.configuration.serializer.ConfigRegion;
import cn.charlotte.pit.util.cooldown.Cooldown;
import cn.charlotte.pit.util.random.RandomUtil;
import com.fastasyncworldedit.core.FaweAPI;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.function.pattern.RandomPattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockTypes;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Cake;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.scheduler.BukkitRunnable;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @Author: EmptyIrony
 * @Date: 2021/2/5 23:37
 */
public class CakeEvent implements IEvent, INormalEvent, Listener {
    private static CuboidRegion[] regions;
    private final DecimalFormat numFormatTwo = new DecimalFormat("0.00");
    private final DecimalFormat df = new DecimalFormat(",###,###,###,###");
    private BukkitRunnable runnable;
    private EditSession session;
    private AxisAlignedBB alignedBB;
    private Map<UUID, CakePlayerData> dataCache;
    /* ---------- 点击频率限制参数 ---------- */
    private static final long CLICK_INTERVAL_MS = 100;   // 正常间隔 ≥100 ms
    private static final long FAST_CLICK_MS     = 50;    // “超速”判定 <50 ms
    private static final int  FAST_CLICK_LIMIT  = 5;     // 连续超速 5 次
    private static final long COOLDOWN_MS       = 5_000; // 冷却 5 s

    /* ---------- 每名玩家的节奏状态 ---------- */
    private final Map<UUID, Long>   lastClickTime = new HashMap<>();
    private final Map<UUID, Integer> fastClicks   = new HashMap<>();
    private final Map<UUID, Long>   cooldownUntil = new HashMap<>();


    public CakeEvent() {
        if (regions == null) {
            PitConfig config = ThePit.getInstance().getPitConfig();
            List<ConfigRegion> cakeZones = config.getCakeZones();
            ConfigRegion cakeRegion = cakeZones.get(RandomUtil.random.nextInt(cakeZones.size()));
            regions = new CuboidRegion[cakeZones.size()];
            for (int i = 0; i < cakeZones.size(); i++) {
                regions[i] = new CuboidRegion(FaweUtils.toBlockVector3(cakeRegion.posA), FaweUtils.toBlockVector3(cakeRegion.posB));
            }


        }
    }

    @Override
    public String getEventInternalName() {
        return "cake";
    }

    @Override
    public String getEventName() {
        return "&d蛋糕争夺战";
    }

    @Override
    public int requireOnline() {
        return NewConfiguration.getEventOnlineRequired().get(getEventInternalName());
    }

    @Override
    public void onActive() {
        lastClickTime.clear();
        fastClicks.clear();
        cooldownUntil.clear();

        CC.boardCast(MessageType.EVENT, "&d蛋糕! &7巨型蛋糕已生成在地图上，吃掉蛋糕获得大量金币和经验!");

        this.dataCache = new HashMap<>();

        final CuboidRegion region = regions[RandomUtil.random.nextInt(regions.length)];
        final BlockVector3 pos1 = region.getPos1();
        final BlockVector3 pos2 = region.getPos2();
        this.alignedBB = new AxisAlignedBB(pos1.x(), pos1.y(), pos1.z(), pos2.x(), pos2.y(), pos2.z());

        FaweAPI.getTaskManager().async(() -> {
            BukkitWorld world = new BukkitWorld(Bukkit.getWorlds().get(0));
            this.session = WorldEdit.getInstance().newEditSession(world);

            final RandomPattern pattern = new RandomPattern();
            pattern.add(new BaseBlock(BlockTypes.CAKE), 0.94);
            pattern.add(new BaseBlock(BlockTypes.MAGENTA_TERRACOTTA), 0.03);
            pattern.add(new BaseBlock(BlockTypes.BLACK_TERRACOTTA), 0.03);

            session.setBlocks((Region) region, pattern);

            session.flushQueue();
        });

        Bukkit.getPluginManager()
                .registerEvents(this, ThePit.getInstance());

        this.runnable = new BukkitRunnable() {
            @Override
            public void run() {
                ThePit.getInstance().getEventFactory().inactiveEvent(CakeEvent.this);
            }
        };

        this.runnable.runTaskLater(ThePit.getInstance(), 20 * 60 * 5);
    }

    @Override
    public void onInactive() {
        FaweAPI.getTaskManager().async(() -> {
            this.session.undo(session);
            this.session.flushQueue();
        });

        HandlerList.unregisterAll(this);

        this.runnable.cancel();

        for (UUID uuid : dataCache.keySet()) {
            if (dataCache.get(uuid).coins >= 5000 && Bukkit.getPlayer(uuid) != null) {
                new CakeEventMedal().addProgress(PlayerProfile.getPlayerProfileByUuid(uuid), 1);
            }
        }
        lastClickTime.clear();
        fastClicks.clear();
        cooldownUntil.clear();
    }

    @EventHandler
    public void onEatCake(PlayerInteractEvent event) {
        if (event.getAction() != Action.RIGHT_CLICK_BLOCK
                && event.getAction() != Action.LEFT_CLICK_BLOCK) {
            return;
        }

        Block block = event.getClickedBlock();
        if (block == null) return;

        Location loc = block.getLocation();
        AxisAlignedBB blockAABB = new AxisAlignedBB(
                loc.getX() - 1, loc.getY() - 1, loc.getZ() - 1,
                loc.getX() + 1, loc.getY() + 1, loc.getZ() + 1);

        if (!alignedBB.intersectsWith(blockAABB)) return;

        Player player = event.getPlayer();
        UUID   uid    = player.getUniqueId();
        long   now    = System.currentTimeMillis();

        Long until = cooldownUntil.get(uid);
        if (until != null && now < until) {
            long remain = (until - now + 999) / 1000;
            player.sendActionBar(CC.translate("&c手速太快了，休息一下吧！"));
            return;
        }

        Long last  = lastClickTime.get(uid);
        long delta = (last == null) ? CLICK_INTERVAL_MS : now - last;

        if (delta < CLICK_INTERVAL_MS) {                 // <100 ms：本次点击无效
            if (delta < FAST_CLICK_MS) {                 // <50 ms：计为超速
                int cnt = fastClicks.getOrDefault(uid, 0) + 1;
                fastClicks.put(uid, cnt);

                if (cnt >= FAST_CLICK_LIMIT) {           // 连续 5 次超速 → 冷却
                    cooldownUntil.put(uid, now + COOLDOWN_MS);
                    fastClicks.put(uid, 0);
                    player.sendActionBar(CC.translate("&c手速太快了，休息一下吧！"));
                }
            }
            return;
        }

        lastClickTime.put(uid, now);
        fastClicks.put(uid, 0);

        PlayerProfile profile = PlayerProfile.getPlayerProfileByUuid(uid);

        CakePlayerData cakeData = dataCache.computeIfAbsent(uid, u -> {
            CakePlayerData d = new CakePlayerData();
            d.uuid = u;
            d.name = player.getDisplayName();
            return d;
        });

        if (!canEat(block.getLocation())) {
            CC.send(MessageType.EVENT, player,
                    "&d&l蛋糕! &c你不能吃里面的蛋糕! 请先吃掉周围的蛋糕!");
            return;
        }

        if (block.getType().toString().endsWith("CAKE")) {
            int baseCoins = 1;

            if (block.getData() == 6) {          // 最后一下
                baseCoins += 5;
                block.setType(Material.AIR);
            } else {                             // 只咬一口
                BlockData data = block.getBlockData();
                if (data instanceof Cake cake) {
                    int clamped = Math.max(0,
                            Math.min(cake.getMaximumBites(), block.getData() + 1));
                    cake.setBites(clamped);
                    block.setBlockData(cake, true);
                }
            }
            block.getState().update();

            double totalCoins = baseCoins;

            cakeData.clicked++;
            cakeData.coins += totalCoins;

            profile.grindCoins(totalCoins);
            profile.setCoins(profile.getCoins() + totalCoins);

            player.playSound(player.getLocation(),
                    Sound.ENTITY_GENERIC_EAT, 1, 1);

            CC.send(MessageType.EVENT, player,
                    "&d&l蛋糕! &6+" + totalCoins + "金币 &d" +
                            cakeData.clicked + "次吃蛋糕 &6(" +
                            numFormatTwo.format(cakeData.coins) +
                            "金币本次事件)");
        }
        else if (block.getType() == Material.BLACK_TERRACOTTA
                || block.getType() == Material.MAGENTA_TERRACOTTA) {

            if (block.getType() == Material.MAGENTA_TERRACOTTA) {          // 樱桃
                block.setType(Material.AIR);

                double totalCoins = 20;
                cakeData.clicked++;
                cakeData.coins += totalCoins;

                profile.grindCoins(totalCoins);
                profile.setCoins(profile.getCoins() + totalCoins);

                player.playSound(player.getLocation(),
                        Sound.ENTITY_GENERIC_EAT, 1, 1);

                CC.send(MessageType.EVENT, player,
                        "&d&l蛋糕! &7吃下了 &c樱桃 &6+20金币&7!");
            } else if (block.getType() == Material.BLACK_TERRACOTTA) { // 巧克力
                block.setType(Material.AIR);

                double totalXp = 20;
                cakeData.clicked++;
                cakeData.coins += totalXp;

                profile.setExperience(profile.getExperience() + totalXp);
                profile.applyExperienceToPlayer(player);

                player.playSound(player.getLocation(),
                        Sound.ENTITY_GENERIC_EAT, 1, 1);

                CC.send(MessageType.EVENT, player,
                        "&d&l蛋糕! &7吃下了 &4巧克力 &b+20经验&7!");
            }
        }
    }


    private boolean canEat(Location location) {
        for (Location face : LocationUtil.getFaces(location)) {
            if (face.getBlock().getType() != Material.CAKE && face.getBlock().getType() != Material.BLACK_TERRACOTTA && face.getBlock().getType() != Material.MAGENTA_TERRACOTTA) {
                return true;
            }
        }
        return false;
    }

    public static class CakePlayerData {
        private UUID uuid;
        private String name;
        private int coins;
        private int clicked;
        private Cooldown cooldown;
    }

}
